package liurong.driver.thread;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class CacheTest {

	private static final ConcurrentHashMap<String, ReentrantLock> CACHE_SEMAPHORE = new ConcurrentHashMap<String, ReentrantLock>();

	private static final ThreadPoolExecutor EXECUTORS = (ThreadPoolExecutor) Executors.newFixedThreadPool(100);

	public static void main(String[] args) throws InterruptedException {

		// 模拟能得到缓存
		final AtomicBoolean flag = new AtomicBoolean(false);

		final AtomicInteger atomicInteger = new AtomicInteger();

		for (int i = 0; i < 100; i++) {

			final String key = getKey(i);
			final ReentrantLock LOCK = getLock(key);
			EXECUTORS.execute(new Runnable() {
				@Override
				public void run() {

					// 防止缓存击穿伪代码
					testCache(flag, atomicInteger);
				}

				private void testCache(AtomicBoolean flag, AtomicInteger atomicInteger) {
					try {
						if (LOCK.tryLock()) {
							try {
								if (flag.get()) {// 代表命中缓存
									atomicInteger.incrementAndGet();
								}
								Thread.sleep(1000);

								// 模拟设置缓存
								flag.compareAndSet(false, true);
							} finally {
								LOCK.unlock();
							}
						} else {
							try {
								LOCK.lock();
								if (flag.get()) {// 代表命中缓存
									atomicInteger.incrementAndGet();
								}
							} finally {
								LOCK.unlock();
							}
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		}

		while (true) {
			if (EXECUTORS.getActiveCount() > 0) {
				System.out.println("活跃线程：" + EXECUTORS.getActiveCount());
			} else if (EXECUTORS.getActiveCount() == 0) {
				break;
			}
		}

		System.out.println("缓存命中：" + atomicInteger.get());
	}

	private static ReentrantLock getLock(String key) {
		ReentrantLock LOCK = CACHE_SEMAPHORE.putIfAbsent(key, new ReentrantLock());
		if (LOCK == null) {// 第一次设置必然为null，所以这里防止第一次获取为null
			LOCK = CACHE_SEMAPHORE.get(key);
		}
		return LOCK;
	}

	private static String getKey(int i) {
		String key;
		if (i % 3 == 0) {
			key = "key0";
		} else if (i % 3 == 1) {
			key = "key1";
		} else {
			key = "key2";
		}
		return key;
	}
}
